package com.contexticon.parser;


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLEventWriter;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.Characters;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartDocument;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;

import com.contexticon.model.Scene;
import com.contexticon.model.Speaker;
import com.contexticon.model.Transcript;
import com.contexticon.model.Utterance;

public class OurParser {
	static final String TRANSCRIPT = "transcript";

	// properties of transcript
	static final String TITLE = "title";
	static final String LANGUAGE = "language";
	static final String TYPE = "type";
	static final String FILEPATH = "mediaPath";

	// properties of a scene
	static final String SCENE = "scene";
	static final String STARTTIME = "startTime";
	static final String ENDTIME =  "endTime";
	static final String SCENETITLE =  "sceneTitle";
	
	// properties of an utterance
	static final String UTTERANCE = "utterance";
	static final String FIDELITY = "fidelity";
	static final String UNCERTAINTY = "uncertainty";
	static final String DEVIANTLANGUAGE =  "deviantLanguage";
	static final String SPEAKER =  "speaker";
	static final String TEXT =  "text";
	static final String CONTENTTAG=  "contentTag";
	static final String LANGUAGETAG=  "languageTag";
	static final String TRANSFERTAG=  "transferTag";
	
	public static TableModel readConfigTable(Transcript t) {

		
		DefaultTableModel model = new DefaultTableModel(new Object[][] {}, new String[] {
				"Beginning", "End", "Text", "Fidelity", "Speaker", "Language tags" , "Content tags", "Transfer tags", "Scene" }){
					Class[] columnTypes = new Class[] { Float.class, Float.class,
							String.class, Float.class, Speaker.class, String.class, String.class, String.class, String.class };

					public Class getColumnClass(int columnIndex) {
						return columnTypes[columnIndex];
					}
				};
				
				
		// loop over scenes
		 for (Scene scene : t.sceneList) {
			 // loop over utterances in the scene
			 for (Utterance utterance : scene.utteranceList) {
				 
				 Float startTime = null;
				 if (utterance.getStartTime()>0) {
					 startTime=utterance.getStartTime();
				 }
				 Float endTime = null;
				 if (utterance.getEndTime()>0) {
					 endTime=utterance.getEndTime();
				 }
				 
				// add a row to the model
				 model.addRow(new Object[] {
							startTime,endTime, utterance.getText(), null, null, null, null, null, null });
			 }// loop over utterances
			 
			 
		 } // end loop over scenes	
				
		return model;
		
	}
	
	
	public static TableModel readConfigTable(String configFile) {
		
		Transcript t = readConfig(configFile);
		System.out.println("Read in the xml transcript");
		System.out.println(t.toString());
		
		DefaultTableModel model = new DefaultTableModel(new Object[][] {}, new String[] {
				"Beginning", "End", "Text", "Fidelity", "Speaker", "Language tags" , "Content tags", "Transfer tags", "Scene" }){
					Class[] columnTypes = new Class[] { Float.class, Float.class,
							String.class, Float.class, Speaker.class, String.class, String.class, String.class, String.class };

					public Class getColumnClass(int columnIndex) {
						return columnTypes[columnIndex];
					}
				};
				
				
		// loop over scenes
		 for (Scene scene : t.sceneList) {
			 // loop over utterances in the scene
			 for (Utterance utterance : scene.utteranceList) {
				 
				 Float startTime = null;
				 if (utterance.getStartTime()>0) {
					 startTime=utterance.getStartTime();
				 }
				 Float endTime = null;
				 if (utterance.getEndTime()>0) {
					 endTime=utterance.getEndTime();
				 }
				 
				// add a row to the model
				 model.addRow(new Object[] {
							startTime,endTime, utterance.getText(), null, null, null, null, null, null });
			 }// loop over utterances
			 
			 
		 } // end loop over scenes	
				
		return model;
		
	}
	
	
	@SuppressWarnings({ "unchecked", "null" })
	public static Transcript readConfig(String configFile) {

		Transcript transcript = new Transcript();
		Scene scene= null;
		Utterance utterance = null;
		
		try {
			// First create a new XMLInputFactory
			XMLInputFactory inputFactory = XMLInputFactory.newInstance();
			// Setup a new eventReader
			InputStream in = new FileInputStream(configFile);
			XMLEventReader eventReader = inputFactory.createXMLEventReader(in);
			// Read the XML document
			//Item item = null;

			while (eventReader.hasNext()) {
				XMLEvent event = eventReader.nextEvent();

				// beginnning of a transcript
				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					// If we have a item element we create a new item
					if (startElement.getName().getLocalPart() == (TRANSCRIPT)) {

						// We read the attributes from this tag and add the date
						// attribute to our object

						Iterator<Attribute> attributes = startElement
								.getAttributes();
						// iterate over attributes
						while (attributes.hasNext()) {
							Attribute attribute = attributes.next();
							if (attribute.getName().toString().equals(TITLE)) {
								transcript.setTitle(attribute.getValue());
							} else if (attribute.getName().toString().equals(LANGUAGE)) {
								transcript.setLanguage(attribute.getValue());
							} else if (attribute.getName().toString().equals(TYPE)) {
								transcript.setType(attribute.getValue());
							} else if (attribute.getName().toString().equals(FILEPATH)) {
								transcript.setFilepath(attribute.getValue());
							}
						}
						continue;


					} 	

				}
				
				// beginning of a scene
				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					// If we have a item element we create a new item
					if (startElement.getName().getLocalPart() == (SCENE)) {

						scene = new Scene();
						// We read the attributes from this tag and add the date
						// attribute to our object

						Iterator<Attribute> attributes = startElement
								.getAttributes();
						// iterate over attributes
						while (attributes.hasNext()) {
							Attribute attribute = attributes.next();
							if (attribute.getName().toString().equals(STARTTIME)) {
								scene.setStartTime(Float.parseFloat(attribute.getValue()));
							} else if (attribute.getName().toString().equals(ENDTIME)) {
								scene.setEndTime(Float.parseFloat(attribute.getValue()));
							} 
						}
						continue;


					} 	

				}
				
				// beginning of a scene title
				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					// If we have a item element we create a new item
					if (startElement.getName().getLocalPart() == (SCENETITLE)) {
						event = eventReader.nextEvent();
						scene.setTitle(event.asCharacters().getData());
						continue;


					} 	

				}
				
				// beginning of an utterance
				if (event.isStartElement()) {
					StartElement startElement = event.asStartElement();
					// If we have a item element we create a new item
					if (startElement.getName().getLocalPart() == (UTTERANCE)) {

						utterance = new Utterance();
						// We read the attributes from this tag and add the date
						// attribute to our object

						Iterator<Attribute> attributes = startElement
								.getAttributes();
						// iterate over attributes
						while (attributes.hasNext()) {
							Attribute attribute = attributes.next();
							if (attribute.getName().toString().equals(FIDELITY)) {
								utterance.setFidelity(Float.parseFloat(attribute.getValue()));
							} else if (attribute.getName().toString().equals(UNCERTAINTY)) {
								utterance.setUncertainty(Boolean.parseBoolean(attribute.getValue()));
							} else if (attribute.getName().toString().equals(STARTTIME)) {
								utterance.setStartTime(Float.parseFloat(attribute.getValue()));
							} else if (attribute.getName().toString().equals(ENDTIME)) {
								utterance.setEndTime(Float.parseFloat(attribute.getValue()));
							} else if (attribute.getName().toString().equals(DEVIANTLANGUAGE)) {
								utterance.setLanguage(attribute.getValue());
							} else if (attribute.getName().toString().equals(SPEAKER)) {
								utterance.setSpeaker(attribute.getValue());
							} 
						}
						continue;


					} 	

				}
				
	
				// check for beginnning of a content tag
				if (event.isStartElement()) {
					if (event.asStartElement().getName().getLocalPart()
							.equals(TEXT)) {
						event = eventReader.nextEvent();
						utterance.setText(event.asCharacters().getData());
						continue;
					}
				}
				
				// check for beginnning of a content tag
				if (event.isStartElement()) {
					if (event.asStartElement().getName().getLocalPart()
							.equals(CONTENTTAG)) {
						event = eventReader.nextEvent();
						utterance.contentTags.add(event.asCharacters().getData());
						continue;
					}
				}
	
				// check for beginnning of a language tag
				if (event.isStartElement()) {
					if (event.asStartElement().getName().getLocalPart()
							.equals(LANGUAGETAG)) {
						event = eventReader.nextEvent();
						utterance.languageTags.add(event.asCharacters().getData());
						continue;
					}
				}
				
				
				// check for beginnning of a teansfer tag
				if (event.isStartElement()) {
					if (event.asStartElement().getName().getLocalPart()
							.equals(TRANSFERTAG)) {
						event = eventReader.nextEvent();
						utterance.transferTags.add(event.asCharacters().getData());
						continue;
					}
				}
				
				
				// check if the event is an end of a scene
				if (event.isEndElement()) {
					EndElement endElement = event.asEndElement();
					if (endElement.getName().getLocalPart() == (SCENE)) {
						transcript.sceneList.add(scene);
					}
				}
				

				// check if the event is an end of a utterance
				if (event.isEndElement()) {
					EndElement endElement = event.asEndElement();
					if (endElement.getName().getLocalPart() == (UTTERANCE)) {
						scene.utteranceList.add(utterance); 
					}
				}
				
				
				
			} // end of while
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (XMLStreamException e) {
			e.printStackTrace();
		}
		return transcript;
	}
	
	public static void writeModelToXML(DefaultTableModel model, String filePath, Transcript transcript) {
		
		//open the file
		try {
			
			
		
			// Create a XMLOutputFactory
			XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
			// Create XMLEventWriter
			XMLEventWriter eventWriter = outputFactory.createXMLEventWriter(new FileOutputStream(filePath), "UTF-8");
			// Create a EventFactory
			
			XMLEventFactory eventFactory = XMLEventFactory.newInstance();
			XMLEvent end = eventFactory.createDTD("\n");
			XMLEvent tab = eventFactory.createDTD("\t");
			// Create and write Start Tag
			StartDocument startDocument = eventFactory.createStartDocument();
			eventWriter.add(startDocument);
			eventWriter.add(end);			
			
			//eventWriter.add(eventFactory.createStartDocument("UTF-8", "1.0"));
			// Create transcript open tag
			StartElement configStartElement = eventFactory.createStartElement("",
					"", "transcript");
			eventWriter.add(configStartElement);
			
			// add the transcript properties
			if (transcript.getFilepath()!=null) {
				eventWriter.add(eventFactory.createAttribute("mediaPath", transcript.getFilepath()));						
			}			
			if (transcript.getType()!=null) {
				eventWriter.add(eventFactory.createAttribute("type", transcript.getType()));						
			}			
			if (transcript.getLanguage()!=null) {
				eventWriter.add(eventFactory.createAttribute("language", transcript.getLanguage()));						
			}			
			if (transcript.getTitle()!=null) {
				eventWriter.add(eventFactory.createAttribute("title", transcript.getTitle()));						
			}		
			
			eventWriter.add(end);
			// Write the different nodes

			// create a default scene
			StartElement sElement = eventFactory.createStartElement("", "", "scene");
			eventWriter.add(tab);
			eventWriter.add(sElement);
			eventWriter.add(end);
			
			int noRows = model.getRowCount();
			for (int r=0; r<(noRows); r++) {
				
				if ((model.getValueAt(r, 2)!=null)) {
				
					String utterance = (String) model.getValueAt(r, 2);
					
					// write the start tag of an utterance
					eventWriter.add(tab);
					
					StartElement utteranceElement = eventFactory.createStartElement("", "", "utterance");
					eventWriter.add(tab);
					eventWriter.add(utteranceElement);	
									
					if (model.getValueAt(r, 0)!=null) {
						String startTime =  model.getValueAt(r, 0).toString();
						eventWriter.add(eventFactory.createAttribute("startTime", startTime));						
					}
	
					if ((model.getValueAt(r, 1)!=null)) {
						String endTime =  model.getValueAt(r, 1).toString();
						eventWriter.add(eventFactory.createAttribute("endTime", endTime));
						
					}

					eventWriter.add(end);
					
					eventWriter.add(tab);eventWriter.add(tab);
					createNode(eventWriter, "text",	utterance);
					
					// write end tag of an utterance
					eventWriter.add(tab); 			eventWriter.add(tab);
					EndElement utteranceEndElement = eventFactory.createEndElement("", "", "utterance");
					eventWriter.add(utteranceEndElement);
					eventWriter.add(end);

					
				}
				
			}

			// end a scene	
			eventWriter.add(tab);
			EndElement eElement = eventFactory.createEndElement("", "", "scene");
			eventWriter.add(eElement);
			eventWriter.add(end);

			eventWriter.add(eventFactory.createEndElement("", "", "transcript"));
			eventWriter.add(end);
			eventWriter.add(eventFactory.createEndDocument());
			eventWriter.close();
			
			
			



		System.out.println("Wrote transcript to "+filePath);

		}
		catch(Exception e) {
			System.out.println("Failed to open the file");
			System.out.println(e.toString());
		}
		
	} // end of writing method
	
	

	
	
	private static void createNode(XMLEventWriter eventWriter, String name,
			String value) throws XMLStreamException {

		XMLEventFactory eventFactory = XMLEventFactory.newInstance();
		XMLEvent end = eventFactory.createDTD("\n");
		XMLEvent tab = eventFactory.createDTD("\t");
		// Create Start node
		StartElement sElement = eventFactory.createStartElement("", "", name);
		eventWriter.add(tab);
		eventWriter.add(sElement);
		// Create Content
		Characters characters = eventFactory.createCharacters(value);
		eventWriter.add(characters);
		// Create End node
		EndElement eElement = eventFactory.createEndElement("", "", name);
		eventWriter.add(eElement);
		eventWriter.add(end);

	}

}